/*
 * Copyright 2008 aileron.cc, Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package cc.aileron.commons.binder;

import static cc.aileron.commons.string.StringExtension.stringExtension;

import java.util.HashMap;
import java.util.Map.Entry;

import cc.aileron.commons.exception.CommandPatternBindException;

import com.google.inject.Binder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

/**
 * コマンドパターン形式の一つのインターフェースクラスに 複数の実態クラスをバインドする際のヘルパークラス
 * 
 * @author Aileron
 * 
 * @param <T>
 */
public class CommandPatternBinder<T>
{
    /**
     * クラスの追加
     * 
     * @param names
     * @return this
     */
    public CommandPatternBinder<T> append(final String... names)
    {
        try
        {
            return doAppend(names);
        }
        catch (final ClassNotFoundException e)
        {
            throw new CommandPatternBindException(e);
        }
    }

    /**
     * バインド
     * 
     * @param binder
     */
    public void bind(final Binder binder)
    {
        for (final Entry<Named, Class<? extends T>> entry : map.entrySet())
        {
            binder.bind(interfaceClass).annotatedWith(entry.getKey()).to(
                    entry.getValue());
        }
    }

    /**
     * doAppend
     * 
     * @param names
     * @return
     * @throws ClassNotFoundException
     */
    private CommandPatternBinder<T> doAppend(final String... names) throws ClassNotFoundException
    {
        for (final String name : names)
        {
            final String className = packageName + "."
                    + stringExtension(name).toCamel().toCapitalize() + suffix;
            map.put(Names.named(name), Class.forName(className).asSubclass(
                    interfaceClass));
        }
        return this;
    }

    /**
     * コマンドパターンのインタフェースクラスを設定
     * 
     * @param interfaceClass
     * @param packageObject
     * @param suffix
     */
    public CommandPatternBinder(
        final Class<T> interfaceClass,
        final Package packageObject,
        final String suffix)
    {
        this.interfaceClass = interfaceClass;
        this.packageName = packageObject.getName();
        this.suffix = suffix;
    }

    /**
     * コマンドパターンインタフェースクラス
     */
    private final Class<T> interfaceClass;

    /**
     * package-name
     */
    private final String packageName;

    /**
     * クラス名のサフィックス
     */
    private final String suffix;

    /**
     * コマンドパターンクラスを保持しておく為の map
     */
    private final HashMap<Named, Class<? extends T>> map = new HashMap<Named, Class<? extends T>>();
}
